package com.jintian.smart.kernel.flowable.flowable.cmd;

import com.jintian.smart.kernel.common.util.StringUtil;
import org.flowable.bpmn.model.UserTask;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.scope.ScopeTypes;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.compatibility.Flowable5CompatibilityHandler;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.impl.persistence.entity.ExecutionEntityManager;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.impl.util.Flowable5Util;
import org.flowable.engine.impl.util.TaskHelper;
import org.flowable.task.api.DelegationState;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;

import java.util.Map;

/**
 * 跳转
 */
public class TaskCompleteCmd implements Command<Void> {

    private final TaskEntity task;
    private final String operator;
    private final Map<String, Object> variables;
    protected final Map<String, Object> transientVariables;

    protected final Map<String, Object> variablesLocal;
    protected final Map<String, Object> transientVariablesLocal;

    public TaskCompleteCmd(TaskEntity task, String operator, Map<String, Object> variables) {
        this(task, operator, variables, null);
    }

    public TaskCompleteCmd(TaskEntity task, String operator, Map<String, Object> variables, Map<String, Object> transientVariables) {
        this(task, operator, variables, null, transientVariables, null);
    }

    public TaskCompleteCmd(TaskEntity task, String operator, Map<String, Object> variables, Map<String, Object> variablesLocal
            , Map<String, Object> transientVariables, Map<String, Object> transientVariablesLocal) {
        this.task = task;
        this.operator = operator;
        this.variables = variables;
        this.variablesLocal = variablesLocal;
        this.transientVariables = transientVariables;
        this.transientVariablesLocal = transientVariablesLocal;
    }

    private void completeTask(TaskEntity task, CommandContext commandContext) {
        // CommandContextUtil.getModelEntityManager(commandContext).
        if (StringUtil.isNotEmpty(task.getScopeId()) && ScopeTypes.CMMN.equals(task.getScopeType())) {
            throw new FlowableException("The task instance is created by the cmmn engine and should be completed via the cmmn engine API");
        }
        // Backwards compatibility
        if (task.getProcessDefinitionId() != null) {
            if (Flowable5Util.isFlowable5ProcessDefinitionId(commandContext, task.getProcessDefinitionId())) {
                Flowable5CompatibilityHandler compatibilityHandler = Flowable5Util.getFlowable5CompatibilityHandler();
                if (transientVariables == null) {
                    if (variablesLocal != null) {
                        compatibilityHandler.completeTask(task, variablesLocal, true);
                    } else {
                        compatibilityHandler.completeTask(task, variables, false);
                    }

                } else {
                    compatibilityHandler.completeTask(task, variables, transientVariables);
                }
                return;
            }
        }
        TaskHelper.completeTask(task, variables, variablesLocal, transientVariables, transientVariablesLocal, commandContext);
    }

    @Override
    public Void execute(CommandContext commandContext) {
        ExecutionEntityManager executionEntityManager = CommandContextUtil.getExecutionEntityManager(commandContext);
        ExecutionEntity currentExecutionEntity = executionEntityManager.findById(task.getExecutionId());
        if (currentExecutionEntity.hasVariable("transform")) {
            UserTask transformUserTask = TransformTaskCmd.createTransformUserTask(currentExecutionEntity.getProcessDefinitionId(),
                    currentExecutionEntity.getProcessDefinitionKey(), task.getTaskDefinitionKey());
            currentExecutionEntity.setCurrentFlowElement(transformUserTask);
            currentExecutionEntity.getParent().setCurrentFlowElement(transformUserTask);
        }

        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            // 委托中
            if (variables != null) {
                task.setVariables(variables);
            }
            if (transientVariables != null) {
                task.setTransientVariables(transientVariables);
            }
            task.setDelegationState(DelegationState.RESOLVED);
            TaskHelper.changeTaskAssignee(task, task.getOwner());
            if (!Boolean.TRUE.equals(this.task.getVariable(TransformTaskCmd.FLAG_TRANSFORM))) {
                this.completeTask(this.task, commandContext);
            }
        } else {
            // 非委派
            if (!StringUtil.equals(task.getAssignee(), this.operator)) {
                TaskHelper.changeTaskAssignee(task, this.operator);
            }
            this.completeTask(this.task, commandContext);
        }

        // 添加环节变量值
        if (this.variables != null) {
            commandContext.getCommandExecutor().execute(new AddHistoricVariableCmd(this.task.getId(),
                    AddHistoricVariableCmd.HistoricVariable_ProcessInstance, this.variables));
        }
        return null;
    }
}